#include "devil1tex.h"
#include <stdio.h>
#include <stdbool.h>

// Print Texture Pack Header.
static void printtph(struct TexturePack*);

// Print Texture Batch Descriptor.
static void printtbd(struct TextureBatchDescriptor*);

// Get Texture Pack Header
static inline bool getpackheader(struct TexturePack**, const char*);

// Get Texture Batch Descriptor.
static bool gettexdescriptor(struct TextureBatchDescriptor**,
                      unsigned int,
                      const char *,
                      unsigned int);

// Get Texture Batch.

static bool gettexbatch(struct TextureBatch**, 
                 unsigned int, 
                 const char*,
                 unsigned int);

// Unpack Texture Batch
static bool unpacktexbatch(struct Texture*,
                    unsigned int,
                    const char*, 
                    const unsigned int);

fn_devil1tex const DEVIL1TEX = {printtph,
                                printtbd,
                                getpackheader,
                                gettexdescriptor,
                                gettexbatch,
                                unpacktexbatch};

static void printtph (struct TexturePack *tp) {
    if (tp != NULL) { 
        printf("id: \t %c %c %c %c \n", tp -> id[3], 
                                        tp -> id[2], 
                                        tp -> id[1], 
                                        tp -> id[0]);
        printf("batch#: \t %i \n",    tp -> batchNumber);
        printf("1st batch: \t %i \n", tp -> firstBatchOffset);
        printf("unknownA: \t %i\n",   tp -> unknownA);
    }
    return;
}

static void printtbd(struct TextureBatchDescriptor *bd) {
    if (bd != NULL) {
        printf("batch index: \t %i \n", bd -> batchIdx);
        printf("hash: \t %u \n",        bd -> hash);
        printf("textures: \t %i\n",     bd -> texNumber);
    }
}

inline static bool getpackheader(struct TexturePack** p, const char *filedata) {
    if (filedata == NULL) {
        return false;
    }
    (*p) = (struct TexturePack*)filedata;
    return true;
}

static bool gettexdescriptor(struct TextureBatchDescriptor **descriptor,
                      unsigned int i,
                      const char *filedata,
                      unsigned int filesize) {
    // starts after the pack header.
    bool done = false;
    unsigned int offset = sizeof(struct TexturePack);
    offset += sizeof(struct TextureBatchDescriptor) * i;
    if (filedata != NULL && offset <= filesize) {
        *descriptor = (struct TextureBatchDescriptor*)(filedata + offset);
        done = true;
    }
    return done;
}

static bool gettexbatch(struct TextureBatch **batch, 
                 unsigned int i, 
                 const char *filedata,
                 unsigned int filesize) {
    struct TexturePack *p = NULL;
    if (!(getpackheader(&p, filedata))) {
        return false;
    }
    if (i > p -> batchNumber) {  // no such batch in texture pack
        return false;
    }
    if (i == 0) {
        *batch = (struct TextureBatch*)(filedata + (p -> firstBatchOffset));
        return true;
    }
    struct TextureBatchDescriptor *d = NULL;
    // find how large are previous batches in total
    // in order to jump to specified texture batch
    unsigned int pastbatchsize = p -> firstBatchOffset;
    unsigned int j;
    for (j = 0; j < i; j++) {
        gettexdescriptor(&d, j, filedata, filesize);
        pastbatchsize += (d -> textureSize * d -> texNumber);
    }
    *batch = (struct TextureBatch*)(filedata + pastbatchsize);
    return true;
}

static bool unpacktexbatch(struct Texture *t,
                    unsigned int i,
                    const char *filedata, 
                    const unsigned int filesize) {
    if (filedata == NULL) {
        return false;
    }
    struct TextureBatch *b           = NULL;
    struct TextureBatchDescriptor *d = NULL;
    gettexbatch(&b, i, filedata, filesize);
    gettexdescriptor(&d, i, filedata, filesize);

    // first texture is at the start of the batch
    // second texture is right after.
    unsigned int j;
    for (j = 0; j < d -> texNumber; j++) {
        t[j].data = (unsigned char*)b + (d -> textureSize * j);
    }
    return true;
}




